package datafile

import (
	"API"
	"errors"
	"io"
	"os"
	"sync"
)

// 数据文件的实现类型
type myDataFile struct {

	// 文件
	f *os.File

	// 被用于文件的读写锁
	fmutex sync.RWMutex

	// 写操作需要用到的偏移量
	woffset int64

	// 读操作需要用到的偏移量
	roffset int64

	// 写操作需要用到的互斥锁
	wmutex sync.Mutex

	// 读操作需要用到的互斥锁
	rmutex sync.Mutex

	// 数据块长度
	dataLen uint32
}

// DataFile的构造函数
func NewDataFile(path string, dataLen uint32) (API.DataFile, error) {
	f, err := os.Create(path)
	if err != nil {
		return nil, err
	}
	if dataLen == 0 {
		return nil, errors.New("Invalid data length!")
	}
	df := &myDataFile{f: f, dataLen: dataLen}
	return df, nil
}

// API中Read()方法实现
// 获取并更新读偏移量
// 根据读偏移量从文中读取一块数据
// 把该数据块封装成一个Data类型值并将其作为结果值返回
// 其中读取并更新偏移量的时候应该由互斥锁rmutex保护起来
func (df *myDataFile) Read() (rsn int64, d API.Data, err error) {
	var offset int64
	df.rmutex.Lock()
	offset = df.roffset
	df.roffset += int64(df.dataLen)
	df.rmutex.Unlock()

	// 读取一个数据块
	rsn = offset / int64(df.dataLen)
	bytes := make([]byte, df.dataLen)
	for {
		df.fmutex.RLock()
		_, err = df.f.ReadAt(bytes, offset)
		if err != nil {
			if err == io.EOF {
				df.fmutex.RUnlock()
				continue
			}
			df.fmutex.RUnlock()
			return
		}
		d = bytes
		df.fmutex.RUnlock()
		return
	}
}

// API中Read()方法实现
func (df *myDataFile) Write(d API.Data) (wsn int64, err error) {
	// 读取并更新写偏移量
	var offset int64
	df.wmutex.Lock()
	offset = df.woffset
	df.woffset += int64(df.dataLen)
	df.wmutex.Unlock()

	// 写入一个数据块
	wsn = offset / int64(df.dataLen)
	var bytes []byte
	if len(d) > int(df.dataLen) {
		bytes = d[0:df.dataLen]
	} else {
		bytes = d
	}
	df.fmutex.RLock()
	defer df.fmutex.RUnlock()
	_, err = df.f.Write(bytes)
	return
}

// API中Rsn()方法实现
func (df *myDataFile) Rsn() int64 {
	df.rmutex.Lock()
	defer df.rmutex.Unlock()
	return df.roffset / int64(df.dataLen)
}

// API中Wsn()方法实现
func (df *myDataFile) Wsn() int64 {
	df.wmutex.Lock()
	defer df.wmutex.Unlock()
	return df.woffset / int64(df.dataLen)
}

// API中DataLen()方法实现
func (df *myDataFile) DataLen() uint32 {
	return df.dataLen
}
